home *** CD-ROM | disk | FTP | other *** search
/ Total Network Tools 2002 / NextStepPublishing-TotalNetworkTools2002-Win95.iso / Archive / Misc Servers / Zope.exe / PCGI-WRAPPER.C < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-01  |  24.0 KB  |  941 lines

  1. /* pcgi-wrapper.c - Persistent CGI wrapper module
  2.  
  3. Copyright (c) 1998, Digital Creations, Fredericksburg, VA, USA.  All
  4. rights reserved. This software includes contributions from Jeff Bauer.
  5.  
  6. Redistribution and use in source and binary forms, with or without
  7. modification, are permitted provided that the following conditions are
  8. met:
  9.  
  10.   o Redistributions of source code must retain the above copyright
  11.     notice, this list of conditions, and the disclaimer that follows.
  12.  
  13.   o Redistributions in binary form must reproduce the above copyright
  14.     notice, this list of conditions, and the following disclaimer in
  15.     the documentation and/or other materials provided with the
  16.     distribution.
  17.  
  18.   o All advertising materials mentioning features or use of this
  19.     software must display the following acknowledgement:
  20.  
  21.       This product includes software developed by Digital Creations
  22.       and its contributors.
  23.  
  24.   o Neither the name of Digital Creations nor the names of its
  25.     contributors may be used to endorse or promote products derived
  26.     from this software without specific prior written permission.
  27.  
  28.  
  29. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS *AS IS* AND
  30. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  31. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  32. PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
  33. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  34. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  35. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  36. BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  37. WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  38. OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  39. IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  40.  
  41. |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
  42.   - 2.0a5  29 October 1998
  43.     - (brian) fixed arg type mismatch for semctl
  44.  
  45.   - 2.0a4  10 August 1998
  46.     - (jeff) fixed Win32 local socket host address issues
  47.  
  48.   - 2.0a4  8 August 1998
  49.     - (jeff) added Win32 support
  50. */
  51. #include "pcgi.h"
  52.  
  53. #ifdef CREOSOTE
  54. #include "creosote.h"  /* used for debugging */
  55. char spewbuf[1024];    /* yes, it's a global, but only for debugging */
  56. #endif
  57.  
  58. static char _id_[]="$Id: pcgi-wrapper.c,v 1.8.4.1 2000/08/01 15:58:45 brian Exp $";
  59.  
  60. /* Globals, OR: "I'll know I'll hate myself in the morning" */
  61. extern char **environ;
  62. int CloseFileDescriptors = 0;
  63.  
  64. #if UNIX
  65. int g_lock = 0;
  66. #endif
  67.  
  68. #if PCGI_WRAPPER_MAIN
  69. int main(int argc, char *argv[])
  70. {   pcgiResource resource;
  71.     pcgiResource *r=&resource;
  72.     long l          =0;
  73.     char t[HDRLEN+1]={0};
  74.     char *estatus   =NULL;
  75.     char *emsg      =NULL;
  76.     char *p         =NULL;
  77.     char **env;
  78.  
  79. #ifdef CREOSOTE
  80.     initializeMrCreosote();
  81.     /* spew("pcgi-wrapper main()"); */
  82. #endif
  83.  
  84. #ifdef CLOSE_FDS
  85.     CloseFileDescriptors = 1;
  86. #endif
  87.  
  88. #ifdef WIN32
  89.     _setmode(fileno(stdin), O_BINARY);
  90.     _setmode(fileno(stdout), O_BINARY);
  91. #endif
  92.  
  93.     /*
  94.     // Initialize resource info
  95.     */
  96.     memset(r,0,sizeof(pcgiResource));
  97.     r->conn=-1;
  98.  
  99.     if (argc < 2) 
  100.     {
  101.         onError(E_500, "No pcgi info file given!", r);
  102.     }
  103.  
  104.     strcpy(r->sw_info, argv[1]);
  105.     if ((pcgiParseInfo(r)) < 0)
  106.     {
  107.         onError(E_500, "Error parsing pcgi info file", r);
  108.     }
  109.  
  110.     /*
  111.     // Copy environment to resource
  112.     */
  113.     for(env=environ; *env != 0; env++)
  114.     {
  115.         r->sz_env+=(strlen(*env)+sizeof(char));
  116.     }
  117.     if((r->p_env=malloc(((sizeof(char) * r->sz_env)+(sizeof(char)*HDRLEN))))==NULL)
  118.     {
  119.         onError(E_500, "Error allocating env", r);
  120.     }
  121.     p=r->p_env;
  122.     sprintf(p, HDRFMT, r->sz_env);
  123.  
  124.     if (p[0] != '0')
  125.     {
  126.         if (!r->errmsg[0])
  127.             strcpy(r->errmsg, ERR123_BAD_ENV_HEADER);
  128.         onError(E_500, "Error allocating env", r);
  129.     }
  130.  
  131.     p+=HDRLEN;
  132.     for(env=environ; *env != 0; env++)
  133.     {   l=strlen(*env);
  134.         memcpy(p, *env, l);
  135.         p+=l;
  136.         *p=0;
  137.         p++;
  138.     }
  139.  
  140.     /*
  141.     // Copy stdin to resource
  142.     */
  143.     p=getenv("CONTENT_LENGTH");
  144.     if((p != NULL) && ((r->sz_input=atol(p)) > 0))
  145.     {  
  146.         if((r->p_input=malloc(((sizeof(char) * r->sz_input)+
  147.                                (sizeof(char)*HDRLEN))))==NULL)
  148.         {
  149.             onError(E_500, "Error allocating stdin", r);
  150.         }
  151.         p=r->p_input;
  152.         sprintf(p, HDRFMT, r->sz_input);
  153.  
  154.         if (p[0] != '0')
  155.         {
  156.             if (!r->errmsg[0])
  157.                 strcpy(r->errmsg, ERR124_BAD_STDIN_HEADER);
  158.             onError(E_500, "Error allocating stdin", r);
  159.         }
  160.  
  161.         p+=HDRLEN;
  162.         if(pcgiRead(STDIN_FILENO, p, r->sz_input) != r->sz_input)
  163.         {
  164.             onError(E_500, "Error reading stdin", r);
  165.         }
  166.     }
  167.     else
  168.     {   
  169.         if((r->p_input=malloc(sizeof(char)*HDRLEN))==NULL)
  170.         {
  171.             onError(E_500, "Error allocating stdin", r);
  172.         }
  173.         sprintf(r->p_input, HDRFMT, 0);
  174.     }
  175.  
  176.     /*
  177.     // Attempt to connect
  178.     */
  179.     if ((r->conn = pcgiConnect(r)) < 0)
  180.     {   
  181.         if(pcgiVerifyProc(r) < 0)
  182.         {   
  183.             if(pcgiStartProc(r) < 0) 
  184.             {
  185.                 if (!r->errmsg[0])
  186.                     strcpy(r->errmsg, ERR101_FAILURE_DURING_START); 
  187.                 onError(E_500, "Failed to start resource", r);
  188.             }
  189.             if ((r->conn=pcgiConnect(r)) < 0)
  190.             {
  191.                 if (!r->errmsg[0])
  192.                     strcpy(r->errmsg, ERR102_FAILURE_DURING_CONNECT); 
  193.                 onError(E_503, strerror(errno), r);
  194.             }
  195.         }
  196.         else
  197.         {   
  198.             if (!r->errmsg[0])
  199.                 strcpy(r->errmsg, ERR103_UNABLE_VERIFY_RUNNING);
  200.             onError(E_503, "pcgiVerifyProc failed", r);
  201.         }
  202.     } 
  203.  
  204.     /*
  205.     // Send environment and stdin
  206.     */
  207. #ifdef WIN32
  208.     if (pcgiWriteSocket(r->conn,r->p_env,(r->sz_env+HDRLEN)) != (r->sz_env+HDRLEN))
  209. #endif
  210. #ifdef UNIX
  211.     if (pcgiWrite(r->conn,r->p_env,(r->sz_env+HDRLEN)) != (r->sz_env+HDRLEN))
  212. #endif
  213.     {
  214.         if (!r->errmsg[0])
  215.             strcpy(r->errmsg, ERR104_ENVIRONMENT_SEND);
  216.         onError(E_500, "Error sending env", r);
  217.     }
  218.  
  219. #ifdef WIN32
  220.     if (pcgiWriteSocket(r->conn,r->p_input,(r->sz_input+HDRLEN)) != (r->sz_input+HDRLEN))
  221. #endif
  222. #ifdef UNIX
  223.     if (pcgiWrite(r->conn,r->p_input,(r->sz_input+HDRLEN)) != (r->sz_input+HDRLEN))
  224. #endif
  225.  
  226.     {
  227.         if (!r->errmsg[0])
  228.             strcpy(r->errmsg, ERR105_STDIN_SEND);
  229.         onError(E_500, "Error sending stdin", r);
  230.     }
  231.  
  232. #ifdef WIN32
  233. shutdown(r->conn, 1); /* shutdown the socket so we can receive */
  234. #endif
  235.  
  236.     /*
  237.     // Receive stdout and stderr
  238.     */
  239.     t[0]='\0';
  240. #ifdef WIN32
  241.     if (!pcgiReadSocket(r->conn, t, HDRLEN))
  242. #endif
  243. #ifdef UNIX
  244.     if (!pcgiRead(r->conn, t, HDRLEN))
  245. #endif
  246.     {
  247.         if (!r->errmsg[0])
  248.             strcpy(r->errmsg, ERR106_STDOUT_READ_HEADER);
  249.         onError(E_503, strerror(errno), r);
  250.     }
  251.  
  252.     if (strlen(t) <= 0)
  253.     {
  254.         if (!r->errmsg[0])
  255.             sprintf(r->errmsg, "%s (%d)", ERR107_BAD_STDOUT_STRLEN, strlen(t));
  256.        onError(E_503, strerror(errno), r);
  257.     }
  258.  
  259.     if (t[0] != '0')
  260.     {
  261.       /* XXX - Later: process this as out-of-bound stdin data */
  262.         sprintf(r->errmsg, "t[0] = %d", (int) t[0]);
  263.         onError(E_500, "unexpected out-of-bound data in stdin", r);
  264.     }
  265.     else
  266.     {
  267.         r->sz_output=atol(t);
  268.         l=(sizeof(char) * r->sz_output) + sizeof(char);
  269.         r->p_output=(char *)malloc(l);
  270.         memset(r->p_output,0,l);
  271. #ifdef WIN32
  272.         if (pcgiReadSocket(r->conn,r->p_output,r->sz_output) != r->sz_output)
  273. #endif
  274. #ifdef UNIX
  275.         if (pcgiRead(r->conn,r->p_output,r->sz_output) != r->sz_output)
  276. #endif
  277.         {
  278.             if (!r->errmsg[0])
  279.                 strcpy(r->errmsg, ERR108_STDOUT_READ_BODY);
  280.             onError(E_500, "Error receiving stdout", r);
  281.         }
  282.     }
  283.  
  284.     t[0]='\0';
  285. #ifdef WIN32
  286.     if (!pcgiReadSocket(r->conn, t, HDRLEN))
  287. #endif
  288. #ifdef UNIX
  289.     if (!pcgiRead(r->conn, t, HDRLEN))
  290. #endif
  291.     {
  292.         if (!r->errmsg[0])
  293.             strcpy(r->errmsg, ERR109_STDERR_READ_HEADER);
  294.         onError(E_500, "Error receiving stderr size", r);
  295.     }
  296.     if (strlen(t) <= 0)
  297.     {
  298.         if (!r->errmsg[0])
  299.             sprintf(r->errmsg, "%s (%d)", ERR110_BAD_STDERR_STRLEN, strlen(t));
  300.         onError(E_500, "Error receiving stderr size", r);
  301.     }
  302.  
  303.     if (t[0] != '0')
  304.     {
  305.       /* XXX - Later: process this as out-of-bound stderr data */
  306.         sprintf(r->errmsg, "t[0] = %d", (int) t[0]);
  307.         onError(E_500, "unexpected out-of-bound data in stderr", r);
  308.     }
  309.     else
  310.     {
  311.         r->sz_error=atol(t);
  312.         if (r->sz_error > 0)
  313.         {   
  314.             l=(sizeof(char) * r->sz_error) + sizeof(char);
  315.             r->p_error=(char *)malloc(l);
  316.             memset(r->p_error,0,l);
  317. #ifdef WIN32
  318.             if (pcgiReadSocket(r->conn, r->p_error, r->sz_error) != r->sz_error)
  319. #endif
  320. #ifdef UNIX
  321.             if (pcgiRead(r->conn, r->p_error, r->sz_error) != r->sz_error)
  322. #endif
  323.             {
  324.                 if (!r->errmsg[0])
  325.                     strcpy(r->errmsg, ERR111_STDERR_READ_BODY);
  326.                 onError(E_500, "Error receiving stderr", r);
  327.             }
  328.         }
  329.     }
  330. #ifdef UNIX
  331.     close(r->conn);
  332. #endif
  333. #ifdef WIN32
  334.     closesocket(r->conn);
  335. #endif
  336.  
  337.     /*
  338.     // Return stdout and stderr to server
  339.     */
  340.     if (r->sz_output != 0)
  341.     {
  342.         if (pcgiWrite(STDOUT_FILENO,r->p_output,r->sz_output) != r->sz_output)
  343.         {
  344.             if (!r->errmsg[0])
  345.                 strcpy(r->errmsg, "(112) Error returning stdout to server"); 
  346.             onError(E_500, ERR112_STDOUT_TO_SERVER, r);
  347.         }
  348.         free(r->p_output);
  349.         r->p_output=NULL;
  350.     }
  351.  
  352.     if (r->sz_error != 0)
  353.     {   
  354.         if (pcgiWrite(STDERR_FILENO,r->p_error,r->sz_error) != r->sz_error)
  355.         {
  356.             if (!r->errmsg[0])
  357.                 strcpy(r->errmsg, ERR113_STDOUT_TO_SERVER);
  358.             onError(E_500, "Error returning stderr", r);
  359.         }
  360.         free(r->p_error);
  361.         r->p_error=NULL;
  362.     }
  363.  
  364.     /*
  365.     // Free env & input buffers, release lock if needed
  366.     */
  367.     free(r->p_env);
  368.     r->p_env=NULL;
  369.     free(r->p_input);
  370.     r->p_input=NULL;
  371.     cleanup();
  372.     fflush(stdout);
  373.     fflush(stderr);
  374.     /*exit(0);*/
  375.     return 0;
  376. }
  377. #endif /* end of main(): PCGI_WRAPPER_MAIN */
  378.  
  379. /*
  380. // onError: fatal pcgi error
  381.  */
  382. void onError(char *estatus, char *emsg, pcgiResource *r)
  383. {
  384.     FILE *f;
  385.     time_t now;
  386. #ifdef VERSION
  387.     /* If VERSION isn't defined as a string, everything will blow up here
  388.        during compilation. */
  389.     char *pcgi_version="pcgi-wrapper-version " VERSION;
  390. #else
  391.     char *pcgi_version = "";
  392. #endif
  393.     char *displayError = "";
  394.  
  395.     if (r != NULL)
  396.     {
  397. #ifdef UNIX
  398.         if(r->conn != -1)    close(r->conn);
  399.         cleanup();
  400. #endif
  401. #ifdef WIN32
  402.         if (r->conn)
  403.         {
  404.             shutdown(r->conn, 1);
  405.             closesocket(r->conn);
  406.             WSACleanup();
  407.         }
  408. #endif
  409.         if (r->errlog[0])
  410.         {   
  411.             if((f=fopen(r->errlog, "ab")) != NULL)
  412.             {
  413.                 now = time(NULL); 
  414.                 fprintf(f, "%s  pcgi-wrapper: %s  %s\n", 
  415.                         ctime(&now), emsg, r->errmsg);
  416.                 fclose(f);
  417.             }
  418.         }
  419.  
  420.         if(r->p_env!=NULL)   free(r->p_env);
  421.         if(r->p_input!=NULL) free(r->p_input);
  422.     }
  423.     if (r->displayErrors)
  424.       displayError = r->errmsg;
  425.     printf(errorHtml, estatus, displayError, emsg, pcgi_version);
  426.     fflush(stdout);
  427.     fflush(stderr);
  428.  
  429.     exit(0);
  430. }
  431.  
  432. /*
  433. // pcgiWrite: write n bytes to a an fd
  434. */
  435. long pcgiWrite(pcgi_socket fd, const char *ptr, long nbytes)
  436. {   
  437.     long done    = 0;
  438.     long notdone = nbytes;
  439.     const char *cptr = (const char *)ptr;
  440.  
  441.     while (notdone > 0)
  442.     {   
  443.         done = write(fd, cptr, notdone);
  444.         if (done <= 0) 
  445.         {
  446.             return (done);
  447.         }
  448.         notdone -= done;
  449.         cptr += done;
  450.     }
  451.     return ((nbytes - notdone));
  452. }
  453.  
  454. #ifdef WIN32
  455. long pcgiWriteSocket(pcgi_socket fd, const char *ptr, long nbytes)
  456. {
  457.     /* The successful completion of a send does not indicate */
  458.     /* that the data was successfully delivered.  */
  459.     int count;
  460.     int req;
  461.     long bytesSent = 0;
  462.  
  463. /* begin superKludge(tm) - only for testing, do not leave in place XXX */
  464. /*     if (STDOUT_FILENO == (int)fd) */
  465. /*     { */
  466. /*         printf("%s", ptr); */
  467. /*         return 0; */
  468. /*     } */
  469. /* end superKludge(tm) - only for testing, do not leave in place XXX */
  470.  
  471.     while ( bytesSent < nbytes )
  472.     {
  473.         req = nbytes - bytesSent;
  474.         count = send(fd, ptr + bytesSent, req, 0);
  475.         if (SOCKET_ERROR == count)
  476.         {
  477.             return(-1);
  478.         }
  479.         bytesSent += (long) count;
  480.     }
  481.  
  482.     return(bytesSent);
  483. }
  484. #endif
  485.  
  486. /*
  487. // pcgiRead: read n bytes from an fd
  488. */
  489. long pcgiRead(pcgi_socket fd, char *ptr, long n)
  490. {   
  491.     long done    = 0;
  492.     long notdone = n;
  493.     char *cptr   = ptr;
  494.  
  495.     while (notdone > 0)
  496.     {   
  497.         done = read(fd, cptr, notdone);
  498.         if (done < 0)       
  499.             return (done);   /* ERROR */
  500.         else if (done == 0) 
  501.             break;           /*  EOF  */
  502.         notdone -= done;
  503.         cptr += done;
  504.     }
  505.     return ((n - notdone));
  506. }
  507.  
  508. #ifdef WIN32
  509. long pcgiReadSocket(pcgi_socket fd, char *ptr, long nbytes)
  510. {
  511.     int count;
  512.     int req;
  513.     long bytesRecv = 0;
  514.  
  515.     while ( bytesRecv < nbytes )
  516.     {
  517.         req = nbytes - bytesRecv;
  518.         count = recv(fd, ptr + bytesRecv, req, 0);
  519.         if (SOCKET_ERROR == count)
  520.         {
  521.             /* TODO: add error reporting by calling WSAGetLastError */
  522.             return(-1);
  523.         }
  524.         bytesRecv += (long) count;
  525.     }
  526.     return(bytesRecv);
  527. }
  528. #endif
  529.  
  530. /*
  531. // pcgiVerifyProc: check to see if a resource is running
  532. */
  533. int pcgiVerifyProc(pcgiResource *r)
  534. {   FILE *f;
  535.     char p[10];
  536.  
  537.     memset(p,0,10);
  538.     if (r->procid == 0)
  539.     {   if((f=fopen(r->procpath, "r")) == NULL)
  540.             return(-1);
  541.         if(fgets(p, HDRLEN, f) == NULL)
  542.             return(-1);
  543.         fclose(f);
  544.         if(!(strlen(p) > 0))
  545.             return(-1);
  546.         r->procid=atoi(p);
  547.     }
  548. #ifdef UNIX
  549.    return(kill(r->procid, 13));
  550. #endif
  551. #ifdef WIN32
  552.     if ((NULL == OpenProcess(PROCESS_VM_READ, FALSE, r->procid)))
  553.     {
  554.         return(-1);
  555.     }
  556.     return(0);
  557. #endif
  558. }
  559.  
  560. /*
  561. // pcgiConnect: return fd of a connected socket
  562. */
  563. #ifdef UNIX
  564. pcgi_socket pcgiConnect(pcgiResource *r)
  565. {   
  566.     struct sockaddr_un s;
  567.     pcgi_socket fd;
  568.     int addrlen=0;
  569.     int connected=-1;
  570.     int attempted=0;
  571.     int retry=10;
  572.     int delay=1;
  573.  
  574.     memset((char *) &s, 0, sizeof(s));
  575.     s.sun_family=AF_UNIX;
  576.     strcpy(s.sun_path, r->sockpath);
  577.  
  578.     addrlen = sizeof(struct sockaddr_un);  /* force to use sizeof(s) */
  579.  
  580.     if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
  581.     {
  582.         if (!r->errmsg[0])
  583.             strcpy(r->errmsg, ERR114_UNABLE_TO_OPEN_SOCKET);
  584.         return (-1);
  585.     }
  586.     while ((connected < 0) && (attempted <= retry))
  587.     {   
  588.         if ((connected=connect(fd, (struct sockaddr *) &s, addrlen)) < 0)
  589.         {   
  590.             if((errno!=ECONNREFUSED) && (errno!=ENOENT))
  591.             {   
  592.                 if (!r->errmsg[0])
  593.                     strcpy(r->errmsg, ERR115_CONNECTION_REFUSED);
  594.                 return(-1);
  595.             }
  596.             sleep(delay);
  597.             attempted++;
  598.         }
  599.     }
  600.     if (!(connected < 0)) 
  601.     {
  602.         if (!r->errmsg[0])
  603.             sprintf(r->errmsg, "%s, fd=%d", ERR116_UNABLE_TO_CONNECT, fd);
  604.         return (fd);
  605.     }
  606.     return (connected);
  607. }
  608. #endif  /* UNIX pcgiConnect */
  609.  
  610.  
  611. #ifdef WIN32
  612. pcgi_socket pcgiConnect(pcgiResource *r)
  613. {
  614.     pcgi_socket destSocket;
  615.     SOCKADDR_IN destSockAddr;
  616.     unsigned long destAddr;
  617.     int connected = SOCKET_ERROR;
  618.     int attempted = 0;
  619.     int status;
  620.     WSADATA WsaData;
  621.  
  622.     char hostName[MAXSZ];
  623.     LPHOSTENT hostEnt;
  624.     SOCKADDR_IN hostAddr;
  625.  
  626.     /* initialize the Windows Socket DLL */
  627.     /* TODO: move this startup code outside of pcgiConnect */
  628.     if (0 != WSAStartup(MAKEWORD(2, 0), &WsaData))
  629.     {
  630.         return(-1);
  631.     }
  632.  
  633.     /* destAddr = inet_addr("192.168.2.43"); */
  634.     hostAddr.sin_addr.s_addr = INADDR_ANY;  /* init local address */
  635.  
  636.     /*  Bug: assumes r->sockhost is the host name, we should also
  637.         check to see if it is the xxx.xxx.xxx.xxx octet string and
  638.         act accordingly */
  639.  
  640.     if (r->sockhost[0])
  641.         strcpy(hostName, r->sockhost);
  642.     else if (SOCKET_ERROR == gethostname(hostName, MAXSZ))
  643.         return(-1);
  644.     hostEnt = gethostbyname((LPSTR) hostName);
  645.     if (hostEnt)
  646.     {
  647.         /* resolve hostname for local address */
  648.         hostAddr.sin_addr.s_addr = *((u_long FAR*) (hostEnt->h_addr));
  649.     }
  650.     if (INADDR_ANY == hostAddr.sin_addr.s_addr)
  651.     {
  652.         return(-1);
  653.     }
  654.     destAddr = hostAddr.sin_addr.s_addr;
  655.  
  656.     memcpy(&destSockAddr.sin_addr, &destAddr, sizeof(destAddr));
  657.     destSockAddr.sin_port = htons((short)r->sockport);
  658.     destSockAddr.sin_family = AF_INET;
  659.  
  660.     /* create socket */
  661.     destSocket = socket(AF_INET, SOCK_STREAM, 0);
  662.     if (INVALID_SOCKET == destSocket)
  663.     {
  664.         return(-1);
  665.     }
  666.  
  667.     /* Connect */
  668.     /*     The code below blithely duplicates the Unix version. */
  669.     /*     TODO:  add better recovery/error handling. */
  670.  
  671.     while ((SOCKET_ERROR == connected) && (attempted <= CONNRETRY))
  672.     {
  673.         connected = connect(destSocket, (LPSOCKADDR) &destSockAddr, sizeof(destSockAddr));
  674.  
  675.         if (SOCKET_ERROR == connected)
  676.         {
  677.             status = WSAGetLastError();
  678.             if ((status != WSAECONNREFUSED) && (status != ENOENT))
  679.             {
  680.                 return(-1);
  681.             }
  682.             sleep(CONNDELAY);
  683.             attempted++;
  684.         }
  685.     }
  686.     if (SOCKET_ERROR == connected)
  687.     {
  688.         closesocket(destSocket);
  689.         WSACleanup();
  690.         return(-1);
  691.     }
  692.  
  693.     return(destSocket);
  694. }
  695. #endif  /* Win32 pcgiConnect */
  696.  
  697.  
  698. #ifdef UNIX
  699. static sig_atomic_t sigflag;
  700. static sigset_t nmask, omask, zmask;
  701. #endif
  702.  
  703. #ifdef UNIX
  704. void pcgiSIG(int s)
  705. {   
  706.     sigflag=1; 
  707.     return;
  708. }
  709. #endif
  710.  
  711. void cleanup()
  712. {   
  713. #ifdef UNIX
  714.     UNION_SEMUN arg;
  715.     arg.val=0;
  716.     if (g_lock > 0) 
  717.     {
  718.         semctl(g_lock, 1, IPC_RMID, arg);
  719.     }
  720. #endif
  721. }
  722.  
  723. /*
  724. // pcgiStartProc: manages starting a pcgi resource.
  725. */
  726. #ifdef UNIX
  727. int pcgiStartProc(pcgiResource *r)
  728. {   
  729.     pid_t pid;
  730.     char  *p = NULL;
  731.     int   i = 0;
  732.     UNION_SEMUN arg;
  733.     arg.val=0;
  734.  
  735.     if ((p=strrchr(r->sw_exe, PATHSEP))==NULL)
  736.     {   
  737.         p = r->sw_exe;
  738.     }
  739.     else
  740.     {   
  741.         p++;
  742.     }
  743.  
  744.     /* Set up signal handlers to coordinate timing */
  745.     signal(SIGUSR1, pcgiSIG);
  746.     signal(SIGUSR2, pcgiSIG);
  747.     sigemptyset(&zmask);
  748.     sigemptyset(&nmask);
  749.     sigaddset(&nmask, SIGUSR1);
  750.     sigaddset(&nmask, SIGUSR2);
  751.     sigprocmask(SIG_BLOCK, &nmask, &omask);
  752.  
  753.     /* Make sure another wrapper isn't already doing a restart */
  754.     if ((r->lock=semget(101, 1, 0700 | IPC_CREAT | IPC_EXCL)) == -1)
  755.     {
  756.         if (errno == EACCES)
  757.             strcpy(r->errmsg, ERR117_LOCK_ERROR_EACCES);
  758.         else if (errno == EEXIST)
  759.             strcpy(r->errmsg, ERR118_LOCK_ERROR_EEXIST);
  760.         else if (errno == EINVAL)
  761.             strcpy(r->errmsg, ERR119_LOCK_ERROR_EINVAL);
  762.         else if (errno == ENOENT)
  763.             strcpy(r->errmsg, ERR120_LOCK_ERROR_ENOENT);
  764.         else if (errno == ENOSPC)
  765.             strcpy(r->errmsg, ERR121_LOCK_ERROR_ENOSPC);
  766.         else
  767.             sprintf(r->errmsg, "%s, %d", ERR122_LOCK_ERROR_OTHER, errno);
  768.         return(-1);
  769.     }
  770.  
  771.     /* Keep us from dying without cleaning up our semaphore by
  772.        setting signal handlers to ensure that the sem will always
  773.        be released. We don't set handlers for SIGUSR1 SIGUSR2 or
  774.        SIGCHLD, because we need those to coordinate with the child
  775.        process(es) that we fork. */
  776.     g_lock = r->lock;
  777.  
  778.     for(i=0; i<32; i++)
  779.     {   
  780.         if ((i!=SIGUSR1) && (i!=SIGUSR2) && (i != SIGCHLD))
  781.         {
  782.             signal(i, (void *)cleanup);
  783.         }
  784.     }
  785.  
  786.     /* If the old socket file exists and we have write permission,
  787.        attempt to remove it. */
  788.     if (r->sockport == 0 && access(r->sockpath, W_OK) == 0)
  789.     {
  790.         unlink(r->sockpath);
  791.     }
  792.  
  793.     /* Fork a child which forks a child -- this is so that
  794.        init will inherit the grandchild (so it won't die) */
  795.     if ((pid = fork()) < 0)
  796.     {   
  797.         semctl(r->lock, 1, IPC_RMID, arg);
  798.         return(-1);
  799.     }
  800.     else if (pid == 0)
  801.     {   
  802.         if ((pid = fork()) < 0) 
  803.         {
  804.             return(-1);
  805.         }
  806.         else if (pid > 0)
  807.         {   /* Let child know we're going away so it can start */
  808.             kill(pid, SIGUSR1);
  809.             exit(0);
  810.         }
  811.  
  812.         setsid();
  813.         chdir("/");
  814.  
  815.         /* Wait for parent to go away */
  816.         while(sigflag == 0) 
  817.             sigsuspend(&zmask);
  818.         sigflag = 0;
  819.         sigprocmask(SIG_SETMASK, &omask, NULL);
  820.  
  821.         /* Platform oddities... */
  822.         if (CloseFileDescriptors)
  823.         {
  824.             close(STDIN_FILENO);
  825.             close(STDOUT_FILENO);
  826.             close(STDERR_FILENO);
  827.         }
  828.  
  829.         execl(r->sw_exe,
  830.               p,
  831.               r->pubpath,
  832.               (char *)0);
  833.         exit(0);           
  834.     }
  835.  
  836.     /* Wait for the first child to finish */
  837.     if (waitpid(pid, NULL, 0) < 0)
  838.     {   semctl(r->lock, 1, IPC_RMID, arg);
  839.         return(-1);
  840.     }
  841.  
  842.     /*
  843.     // Release restart lock!
  844.     */
  845.     semctl(r->lock, 1, IPC_RMID, arg);
  846.  
  847.     /*
  848.     // Reset signal handlers
  849.     */
  850.     for(i=0; i<10; i++) 
  851.     {
  852.         signal(i, SIG_DFL);
  853.     }
  854.  
  855.     sleep(2);
  856.     return (0);
  857. }
  858. #endif  /* UNIX pcgiStartProc */
  859.  
  860. #ifdef WIN32
  861. int pcgiStartProc(pcgiResource *r)
  862. {
  863.     HANDLE mutex = 0;
  864.     char pythonExecutable[256];
  865.     char command_line[1024];
  866.     BOOL createProcessStatus;
  867.     STARTUPINFO StartupInfo;
  868.     PROCESS_INFORMATION ProcessInfo;
  869.     int waitStatus;
  870.  
  871.     GetStartupInfo(&StartupInfo);
  872.  
  873.     /* Is another wrapper attempting a restart? */
  874.     mutex = CreateMutex(NULL, FALSE, MUTEX_NAME);
  875.     if (NULL == mutex)
  876.     {
  877.         //TODO: add error reporting
  878.         return(-1);
  879.     }
  880.  
  881.     waitStatus = WaitForSingleObject(mutex, (AUTODELAY * 1000));
  882.     if (WAIT_TIMEOUT == waitStatus)
  883.     {
  884.         //TODO: add error reporting
  885.         return(-1);
  886.     }
  887.     else if (WAIT_FAILED == waitStatus)
  888.     {
  889.         //TODO: add error handling by calling GetLastError()
  890.         return(-1);
  891.     }
  892.  
  893.     /*
  894.     Travel beyond this point requires calling the
  895.     ReleaseMutex function.  Fortunately, the Win32
  896.     mutex is automatically released when a process
  897.     terminates, but we could still encounter a
  898.     situation where the process is hung or stalled ...
  899.     */
  900.  
  901.   if (r->sw_exe[0])
  902.       strcpy(pythonExecutable, r->sw_exe);
  903.   else
  904.     strcpy(pythonExecutable, "python");
  905.  
  906.     sprintf(command_line, "%s %s", pythonExecutable, r->pubpath);
  907.  
  908.     createProcessStatus = CreateProcess(
  909.         NULL,
  910.         command_line,
  911.         NULL,
  912.         NULL,
  913.         FALSE,
  914.         DETACHED_PROCESS,
  915.         NULL,
  916.         NULL,
  917.         &StartupInfo,
  918.         &ProcessInfo);
  919.  
  920.      /* wait a little bit to give the published
  921.      application enough time to initialize itself */
  922.  
  923. //Yech!!!
  924.     sleep(AUTODELAY); // <<<-- use a ReadySignal(tm), if available :)
  925.  
  926.     ReleaseMutex(mutex);
  927.     CloseHandle(mutex);
  928.  
  929.     if (0 == createProcessStatus)
  930.     {
  931.         //TODO: report more information about failure
  932.         return(-1);
  933.     }
  934.     else
  935.     {
  936.         r->procid = ProcessInfo.dwProcessId; /* assign process id */
  937.         return(0);
  938.     }
  939. }
  940. #endif
  941.